# -*- encoding: utf-8 -*-
"""
@File    : abstract_factory.py
@Author  : lilong
@Time    : 2021/12/17 10:08 上午
"""

"""
参考：https://www.cnblogs.com/leetao94/p/13291508.html

接着上一篇的故事工厂模式继续，手机要出厂，显然光一个手机肯定是不行的，还需要包装盒、充电器等等东西。
我们按照上一篇提到的工厂模式，去建立新的配件工厂、配件类是一点都没有问题的。
但是思考一下这样子做会带来的问题，显然工厂太多了，将包装盒、充电器全部分散到各个工厂，组装什么的也是一个大问题，
那么有没有更好的办法呢？

答案是肯定的，抽象工厂模式。

把一个类型的手机所需要的所有东西，都放到一个工厂完成，小米工厂生产小米手机以及小米手机配套的东西，
苹果手机生产苹果手机以及苹果手机配套的东西，客户只需要关心要什么手机就行了。

# 组成
抽象工厂类+产品工厂类：手机工厂+配件工厂
抽象产品类+具体产品类：


总结：
如果代码需要与多个不同系列的相关产品交互， 但是由于无法提前获取相关信息， 或者出于对未来扩展性的考虑， 
你不希望代码基于产品的具体类进行构建， 在这种情况下， 你可以使用抽象工厂。

在程序中每个类仅负责一件事。 如果一个类与多种类型产品交互， 就可以考虑将工厂方法抽取到独立的工厂类或具备完整功能的抽象工厂类中。

抽象工厂的优缺点：
优点：
你可以确保同一工厂生成的产品相互匹配。
你可以避免客户端和具体产品代码的耦合。
单一职责原则。 你可以将产品生成代码抽取到同一位置， 使得代码易于维护。
开闭原则。 向应用程序中引入新产品变体时， 你无需修改客户端代码

缺点：
由于采用该模式需要向应用中引入众多接口和类， 代码可能会比之前更加复杂，即产品族扩展非常困难。
"""

from abc import ABC, abstractmethod


# -------产品类-------

class AbstractMobile(ABC):
    """抽象产品类"""

    @abstractmethod
    def make(self):
        pass


class XiaoMiMobile(AbstractMobile):
    """小米手机类"""

    def make(self):
        print("make xiaomi mobile")


class AppleMobile(AbstractMobile):
    """苹果手机类"""

    def make(self):
        print("make apple mobile")


class AbstractOthers(ABC):
    """手机配件抽象类"""

    @abstractmethod
    def make(self):
        pass


class XiaoMiOthers(AbstractOthers):
    """小米配件类"""

    def make(self):
        print("make xiaomi others")


class AppleOthers(AbstractOthers):
    """苹果配件类"""

    def make(self):
        print("make apple others")


# ---------工厂类----------
class AbstractFactory(ABC):
    """抽象工厂类"""

    @abstractmethod
    def create_mobile(self) -> AbstractMobile:
        pass

    @abstractmethod
    def create_others(self) -> AbstractOthers:
        pass


class XiaoMiFactory(AbstractFactory):
    """小米工厂类
        生产手机+生产配件
    """

    def create_mobile(self) -> XiaoMiMobile:
        return XiaoMiMobile().make()

    def create_others(self) -> XiaoMiOthers:
        return XiaoMiOthers().make()


class AppleFactory(AbstractFactory):
    """苹果工厂类
        生产手机+生产配件
    """

    def create_mobile(self) -> AppleMobile:
        return AppleMobile().make()

    def create_others(self) -> AppleOthers:
        return AppleOthers().make()


# ----------客户端------
def client(factory: AbstractFactory) -> None:
    """定义客户端需要的逻辑
    可任意修改，不会影响产品工厂和产品配件
    """
    product_mobile = factory.create_mobile()
    product_others = factory.create_others()


if __name__ == "__main__":
    client(XiaoMiFactory())
    client(AppleFactory())
